﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;
using System.Xml.Linq;
using System.Data.OracleClient;
using MySql.Data.MySqlClient;

//using Oracle.DataAccess.Client;

namespace SHARED
{
    public class BuildTree
    {
        //public void UsedForTestingOnly()
        //{
        //     string serverName = " callisto.ccec.unf.edu";
        //    string dbName = "COP6711_2012_TeamA1";
        //    string userID = "n00669880 ";
        //    string pwd = "ikaddourpassword";
        //    IDb msSql =  new MYSQL(serverName, dbName, userID, pwd);

        //    Element rootEl = new Element("Results");
        //    MasterElement rootMasterElement = new MasterElement(0);
        //    rootMasterElement.elements.Add(rootEl);

        //    //master element -> level 1
        //    Element SysStem = new Element("DepartmentName", true);
        //    Element SystemInfo = new Element("Name");
        //    MasterElement Systems = new MasterElement(1);
        //    Systems.AddElement(SysStem);
        //    Systems.AddElement(SystemInfo);
        //    Systems.Parent = rootMasterElement;

        //    //master element -> level 2
        //    Element systemID = new Element("Physicianinfo", true);
        //    Element AppID = new Element("FirstName");
        //    Element ZipCode = new Element("LastName");
        //    MasterElement sysDetails = new MasterElement(2);
        //    sysDetails.AddElement(systemID);
        //    sysDetails.AddElement(AppID);
        //    sysDetails.AddElement(ZipCode);
        //    sysDetails.Parent = Systems;

        //    MasterElementList list = new MasterElementList(rootMasterElement);
        //    list.Add(Systems);
        //    list.Add(sysDetails);

        //    //OracleCommand com = new OracleCommand();
        //    MySqlCommand com = new MySqlCommand();
        //    com.CommandText = "Select Department.Name, Physician.FirstName, Physician.LastName FROM Department, Physician Where Department.DeptNo = Physician.DeptNo"; //Department.DepartmentNumber = Physician.DepartmentNumber
        //    //msSql.ExecuteSelectCommand(com);
        //    MasterElementList result = msSql.ExecuteSelectCommandObject(com, list, rootMasterElement);

        //    XElement e = GenerateXMLUsingCompressionTechnique(result);
        //    e.Save(AppDomain.CurrentDomain.BaseDirectory + @"\AAA.xml");
        //}

        /// <summary>
        /// Queries the database and builds the tree based on the provided schema.
        /// </summary>
        /// <param name="establishedConnection">connection is already established at this level and it should be provided to the algorithm</param>
        /// <param name="selectStatement">dbCommand that has the select statement</param>
        /// <param name="schema">schema</param>
        /// <param name="root">root MasterElement (level 0)</param>
        /// <returns></returns>
        public MasterElementList BuildTreeFromDatabase(IDb establishedConnection, IDbCommand selectStatement, MasterElementList schema, MasterElement root)
        {
            try
            {
                if (establishedConnection == null)
                {
                    throw new Exception("Please establish a connection in order to generate the file");
                }
                if (root == null || root.level != 0 || selectStatement == null || schema == null || schema.Count == 0)
                {
                    throw new ArgumentException();
                }
                MasterElementList result = establishedConnection.ExecuteSelectCommandObject(selectStatement, schema, root);
                return result;

            }
            catch
            {
                throw;
            }
        }

        /// <summary>
        /// Generate the xml file using the compression technique.
        /// </summary>
        /// <param name="masterList">list buit by BuildTree method</param>
        /// <returns>xml document</returns>
        public XElement GenerateXMLUsingCompressionTechnique(MasterElementList masterList)
        {
            try
            {
                XElement doc = new XElement(masterList[0].Parent.elements[0].tagName);

                for (int i = 0; i < masterList.Count; i++)
                {
                    if (masterList[i].level == 1)
                    {

                        XElement record = new XElement(masterList[i].elements[0].tagName);
                        doc.Add(CompressionAlgo(masterList[i], record));
                    }
                }

                return doc;
            }
            catch
            {
                throw;
            }
        }

        /// <summary>
        /// Generate the xml file using the compression technique. It requires that the user provides the leaf level number.
        /// </summary>
        /// <param name="masterList"></param>
        /// <param name="leafLevelNumber"></param>
        /// <returns></returns>
        public XElement GenerateXMLUsingGroupingTechnique(MasterElementList masterList, int leafLevelNumber)
        {
            try
            {
                XElement doc = new XElement(masterList[0].Parent.elements[0].tagName);

                for (int i = 0; i < masterList.Count; i++)
                {
                    if (masterList[i].level == leafLevelNumber)
                    {

                        XElement leaf = new XElement(masterList[i].elements[0].tagName);

                        for (int j = 1; j < masterList[i].elements.Count; j++)
                        {
                            XElement temp = new XElement(masterList[i].elements[j].tagName, masterList[i].elements[j].tagValue);
                            XAttribute table = new XAttribute("table", masterList[i].elements[j].tableName);
                            XAttribute type = new XAttribute("Type", masterList[i].elements[j].tagType);
                            XAttribute length = new XAttribute("Length", masterList[i].elements[j].columnSize);
                            XAttribute baseColumnName = new XAttribute("BaseColumnName", masterList[i].elements[j].baseColumnName);
                            temp.Add(type);
                            temp.Add(length);
                            temp.Add(table);
                            temp.Add(baseColumnName);
                            leaf.Add(temp);
                        }

                        doc.Add(GroupingAlgo(masterList[i], leaf));
                    }
                }
                return doc;
            }
            catch (Exception)
            {
                
                throw;
            }

        }

        /// <summary>
        /// recursive method that generate the xml document using compression
        /// </summary>
        /// <param name="me"></param>
        /// <param name="el"></param>
        /// <returns></returns>
        private XElement CompressionAlgo(MasterElement me, XElement el)
        {
            try
            {
                if (me.Children.Count >= 0)
                {
                    for (int i = 1; i < me.elements.Count; i++)
                    {
                        XElement temp = new XElement(me.elements[i].tagName, me.elements[i].tagValue);
                        XAttribute table = new XAttribute("table", me.elements[i].tableName);
                        XAttribute type = new XAttribute("Type", me.elements[i].tagType);
                        XAttribute length = new XAttribute("Length", me.elements[i].columnSize);
                        XAttribute baseColumnName = new XAttribute("BaseColumnName", me.elements[i].baseColumnName);
                        temp.Add(type);
                        temp.Add(length);
                        temp.Add(table);
                        temp.Add(baseColumnName);
                        el.Add(temp);

                    }
                }
                for (int i = 0; i < me.Children.Count; i++)
                {
                    if (me.Children[i].elements[0].tagName != string.Empty)
                    {
                        XElement el1 = new XElement(me.Children[i].elements[0].tagName);
                        el.Add(CompressionAlgo(me.Children[i], el1));
                    }
                    else
                    {
                        CompressionAlgo(me.Children[i], el);
                    }
                }

                return el;
            }
            catch
            {
                throw;
            }

        }

        /// <summary>
        /// recursive method that generate the xml document by grouping the masterelements that belong to the same parent
        /// </summary>
        /// <param name="me">masterElement of the leaf</param>
        /// <param name="c">xelement of the leaf</param>
        /// <returns>Xelement of the record</returns>
        private XElement GroupingAlgo(MasterElement me, XElement c)
        {
            XElement xel = null;
            while (me.Parent.level != 0)
            {
                xel = new XElement(me.Parent.elements[0].tagName);
                MasterElement e = me.Parent;
                //XElement xel = new XElement(e.elements[0].tagName);
                for (int i = 1; i < e.elements.Count; i++)
                {
                    XElement temp = new XElement(e.elements[i].tagName, e.elements[i].tagValue);
                    XAttribute table = new XAttribute("table", e.elements[i].tableName);
                    XAttribute type = new XAttribute("Type", e.elements[i].tagType);
                    XAttribute length = new XAttribute("Length", e.elements[i].columnSize);
                    XAttribute baseColumnName = new XAttribute("BaseColumnName", e.elements[i].baseColumnName);
                    temp.Add(type);
                    temp.Add(length);
                    temp.Add(table);
                    temp.Add(baseColumnName);
                    xel.Add(temp);
                }
                xel.Add(c);
                if (e.Parent.level != 0)
                {
                    return GroupingAlgo(e, xel);
                }
                else
                {
                    break;
                }
            }
            return xel;
        }


        
    }
}
